#include "ThreadPool.h"
#include "Logger.h"

#include <iostream>

ThreadPool::ThreadPool()
	: initThreadSize_(0)
	, curThreadSize_(0)
	, idleThreadSize_(0)
	, taskSize_(0)
	, taskQueMaxThresHold_(TASK_MAX_THRESHOLD)
	, poolMode_(PoolMode::MODE_FIXED)
	, isPoolRunning_(false)
	, threadSizeThresHold_(THREAD_MAX_THRESHOLD)
{}

ThreadPool::~ThreadPool()
{
	isPoolRunning_ = false;

	// 等待线程池中所有的线程返回 -> 有两种状态：阻塞 & 正在执行任务中
	std::unique_lock<std::mutex> lock(taskQueMtx_);
	notEmpty_.notify_all();
	exitCond_.wait(lock, [&]()->bool { return threads_.size() == 0; });

    LOG_INFO("ThreadPool::~ThreadPool(). \n");
}

// 支持用户设置线程池的工作模式
void ThreadPool::setMode(PoolMode mode)
{
    // 运行过程无法修改线程池状态
	if (checkRunningState())
	{
        LOG_INFO("ThreadPool is running, ThreadPool::setMode failed. \n");
        return;
    }

    poolMode_ = mode;
}

// 支持用户设置任务队列的上限阈值
void ThreadPool::setTaskQueMaxThresHold(int threshold)
{
    // 运行过程无法修改线程池状态
	if (checkRunningState())
	{
        LOG_INFO("ThreadPool is running, ThreadPool::setTaskQueMaxThresHold failed. \n");
        return;
    }

    taskQueMaxThresHold_ = threshold;
}

// 支持用户设置线程池cached模式下线程上限阈值
void ThreadPool::setThreadSizeThresHold(int threshold)
{
    // 运行过程无法修改线程池状态
	if (checkRunningState())
	{
        LOG_INFO("ThreadPool is running, ThreadPool::setThreadSizeThresHold failed. \n");
        return;
    }

    if (poolMode_ == PoolMode::MODE_CACHED)
    {
        threadSizeThresHold_ = threshold;
    }
}

// 开启线程池函数
void ThreadPool::start(int initThreadSize)
{
	// 设置线程池的运行状态
	isPoolRunning_ = true;

	// 记录初始线程个数
	initThreadSize_ = initThreadSize;
	curThreadSize_ = initThreadSize;

    LOG_INFO("ThreadPool::start running. \n");

	// 创建线程对象
	for (int i = 0; i < initThreadSize_; i++)
	{
		// 创建thread线程对象时，通过绑定器把线程函数给到thread线程对象
		auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1));
		int threadId = ptr->getId();
		threads_.emplace(threadId, std::move(ptr));
	}

	// 启动所有线程 → 需要执行线程函数
	for (int i = 0; i < initThreadSize_; i++)
	{
		// threads_[i]->start(); // 需要执行一个线程函数
		threads_[i]->start(); // 需要执行一个线程函数
		idleThreadSize_++; // 记录初始空闲线程的数量
	}
}

// 线程函数
void ThreadPool::threadFunc(int threadId)
{
	auto lastTime = std::chrono::high_resolution_clock().now();

	// 所有任务必须执行完成，线程池才可以回收所有线程资源
	for (;;)
	{
		Task task;
		{
			// 获取锁
			std::unique_lock<std::mutex>lock(taskQueMtx_);

		    LOG_INFO("tid:%llu start getting task. \n", std::this_thread::get_id());

			// cahced模式下，可能已经创建了很多线程，但空闲时间超过60s，应该回收多余的线程
			// 每秒返回一次 -> 如何区分超时返回 or 有任务待执行返回
			while (taskQue_.size() == 0)
			{
				// 线程池结束，回收线程资源
				if (!isPoolRunning_)
				{
					threads_.erase(threadId);
					exitCond_.notify_all();
                    LOG_INFO("threadid:%llu exit! \n", std::this_thread::get_id());
					exitCond_.notify_all();
					return; // 线程函数结束，线程退出
				}

				if (poolMode_ == PoolMode::MODE_CACHED)
				{
					// 条件变量超时返回
					if (std::cv_status::timeout == notEmpty_.wait_for(lock, std::chrono::seconds(1)))
					{
						auto now = std::chrono::high_resolution_clock().now();
						auto dur = std::chrono::duration_cast<std::chrono::seconds>(now - lastTime);
						if (dur.count() >= THREAD_MAX_IDLE_TIME && curThreadSize_ > initThreadSize_)
						{
							// 开始回收当前线程
							// 修改线程数量相关的值
							// 将线程对象从线程列表容器中删除（threadID - 线程对象）
							threads_.erase(threadId);
							curThreadSize_--;
							idleThreadSize_--;

							LOG_INFO("threadid:%llu exit! \n", std::this_thread::get_id());

							return;
						}
					}
				}
				else
				{
					// 等待notEmpty_条件
					notEmpty_.wait(lock);
				}
			}

			idleThreadSize_--;

			LOG_INFO("tid:%llu get task succeed. \n", std::this_thread::get_id());

			// 从任务队列中取一个任务
			task = taskQue_.front();
			taskQue_.pop();
			taskSize_--;

			// 若仍有剩余任务，继续通知其它线程执行任务
			if (taskQue_.size() > 0)
			{
				notEmpty_.notify_all(); // 通知阻塞在notEmpty信号量上的线程
			}

			// 取出一个任务，进行通知
			notFull_.notify_all(); // 通知阻塞在notFull信号量上的线程

		} // unique_lock出了作用域即可释放锁 -> 防止线程在执行任务过程中一直“占用”锁

		// 当前线程负责执行任务
		if (task != nullptr)
		{
			task();
		}
		idleThreadSize_++;
		auto lastTime = std::chrono::high_resolution_clock().now(); // 更新线程执行完任务的时间
	}
}